The backstage of reactivity
by Nick aka malyvsen
xxxxxxxxxx
Hey there 👋 In this notebook, I'll try to convince you that you could have made Pluto yourself!
This notebook is part of PlutoCon 2021. It's best served together with my presentation 🎥
xxxxxxxxxx
Expression objects
If you write a colon :
in front of some code, you get an expression object representing the syntax tree.
xxxxxxxxxx
:(toucan = 2 + can)
xxxxxxxxxx
:(toucan = 2 + can)
This object has a .head
and .args
, which represent a node in the syntax tree and its children. In this case, .head
is the assignment operator =
and the children are the left-hand side (the variable being assigned to) and the right-hand side (the value being assigned).
xxxxxxxxxx
:(=)
xxxxxxxxxx
:(toucan = 2 + can).head
:toucan
:(2 + can)
xxxxxxxxxx
The :toucan
you're seeing here is a symbol object - it represents a variable name and can easily be turned into a string:
xxxxxxxxxx
"toucan"
xxxxxxxxxx
Also, check this out: args[2]
is an expression object in itself!
xxxxxxxxxx
:(2 + can)
xxxxxxxxxx
Now for a little it of Julia magic: 2 + can
is a function call to the function +
:
xxxxxxxxxx
:call
xxxxxxxxxx
:+
2
:can
xxxxxxxxxx
.args[1]
is the function being called, and the rest of .args
is its arguments. So +
is secretly a function!
xxxxxxxxxx
7
xxxxxxxxxx
One last thing about expression objects - you can easily make them out of strings like so:
xxxxxxxxxx
:(toucan = 2 + can)
xxxxxxxxxx
What variables does a cell use?
Let's write a function, references
, which tells us exactly that!
xxxxxxxxxx
:+
:can
xxxxxxxxxx
references (generic function with 1 method)
xxxxxxxxxx
references (generic function with 2 methods)
xxxxxxxxxx
references (generic function with 3 methods)
xxxxxxxxxx
What variables does a cell assign to?
xxxxxxxxxx
:can
xxxxxxxxxx
assignments (generic function with 1 method)
xxxxxxxxxx
When does one cell depend on another?
We'll write a function called depends_on
which tells us whether cell a
depends on cell b
, i.e. whether b
needs to be ran before a
.
It's pretty easy! Try to figure it out before you proceed 🧙🏼 Here's how our function should behave:
xxxxxxxxxx
true
xxxxxxxxxx
false
xxxxxxxxxx
Tell me how it's done!
xxxxxxxxxx
TypeError: non-boolean (Missing) used in boolean context
- top-level scope@Local: 1
xxxxxxxxxx
depends_on (generic function with 1 method)
xxxxxxxxxx
In what order should we run cells?
Julia's sort
function can help here - it takes a "less than" argument, lt
, which should be a function that returns true
if its first argument should come before its second argument, and false
otherwise.
xxxxxxxxxx
run_order (generic function with 1 method)
xxxxxxxxxx
"can = 3"
"toucan = 2 + can"
"cat = toucan"
xxxxxxxxxx
Actually running cells
Let's use Julia's Core.eval
to run cells in the correct order.
The first argument to Core.eval
is the module to evaluate the expression in - we'll just use Main
. The second argument is an expression object.
xxxxxxxxxx
run_cell! (generic function with 1 method)
xxxxxxxxxx
3
xxxxxxxxxx
3
xxxxxxxxxx
We're almost there! The cells below are quite meta, so Pluto might have trouble updating them - please help it 😇
xxxxxxxxxx
run_cells! (generic function with 1 method)
xxxxxxxxxx
4
6
xxxxxxxxxx
4
xxxxxxxxxx
6
xxxxxxxxxx
Bam, we did it! I hope Pluto is still magic 🪄 after you got a sneak peek behind the curtain. Adieu!
xxxxxxxxxx